10 #define forn(i, n) for (int i = 0; i < (n); i++)
11 #define TOLERANCIA 1e-8
19 MaybeDouble(long double v
, bool b
): valor(v
), valido(b
) {};
26 Vector(long double xi
, long double yi
): x(xi
), y(yi
) {};
32 long double angulo() {
42 Columna(long double x
, long double y
, long double r
) : posicion(x
,y
), radio(r
) {};
45 typedef Vector Lampara
;
46 typedef pair
<long double, long double> Intervalo
;
47 typedef pair
<Vector
, Vector
> Segmento
;
50 inline long double largo(const Segmento
& s
) {
51 return Vector(s
.second
.x
- s
.first
.x
, s
.second
.y
- s
.first
.y
).norma();
54 inline long double largo(const Intervalo
& i
) {
55 assert(i
.first
<= i
.second
);
56 return i
.second
- i
.first
;
60 MaybeDouble
intersect_segments(const Segmento
& s1
, const Segmento
& s2
) {
62 Vector p2
= s1
.second
;
64 Vector p4
= s2
.second
;
66 long double den
= (p4
.y
-p3
.y
)*(p2
.x
-p1
.x
) - (p4
.x
-p3
.x
)*(p2
.y
-p1
.y
);
68 long double ua_num
= (p4
.x
-p3
.x
)*(p1
.y
-p3
.y
) - (p4
.y
-p3
.y
)*(p1
.x
-p3
.x
);
69 long double ub_num
= (p2
.x
-p1
.x
)*(p1
.y
-p3
.y
) - (p2
.y
-p1
.y
)*(p1
.x
-p3
.x
);
71 if (fabs(den
) < TOLERANCIA
) {
72 // Caso en que los segmentos son paralelos
73 if (fabs(ua_num
- ub_num
) < TOLERANCIA
&& fabs(ub_num
) < TOLERANCIA
) {
74 // Las rectas son coincidentes, esto no deberia ocurrir
76 return MaybeDouble((p1
.norma() > p2
.norma()? 0 : 1), true);
78 return MaybeDouble(0, false);
81 if (ub_num
/den
>= 0) {
82 return MaybeDouble(ua_num
/den
, true);
84 return MaybeDouble(0, false);
88 Intervalo
interseccion_intervalos(const Intervalo
& i1
, const Intervalo
& i2
) {
90 long double d0
= max(i1
.first
, i2
.first
);
91 long double d1
= min(i1
.second
, i2
.second
);
94 return Intervalo(0, 0);
96 return Intervalo(d0
, d1
);
101 Intervalo
rango_oscurecido(const Segmento
& pared
, const Lampara
& lampara
, const Columna
& columna
) {
102 Vector
bisectriz(columna
.posicion
.x
- lampara
.x
, columna
.posicion
.y
- lampara
.y
);
103 long double p
= asin(columna
.radio
/bisectriz
.norma());
104 long double alpha
= bisectriz
.angulo();
106 Vector
d1(cos(alpha
+ p
), sin(alpha
+ p
));
107 Vector
d2(cos(alpha
- p
), sin(alpha
- p
));
109 MaybeDouble p1
= intersect_segments(pared
, Segmento(lampara
, Vector(lampara
.x
+ d1
.x
, lampara
.y
+ d1
.y
)));
110 MaybeDouble p2
= intersect_segments(pared
, Segmento(lampara
, Vector(lampara
.x
+ d2
.x
, lampara
.y
+ d2
.y
)));
111 printf("p1 = [%d, %Lf]\n", p1
.valido
, p1
.valor
);
112 printf("p2 = [%d, %Lf]\n", p2
.valido
, p2
.valor
);
115 long double unidad
= largo(pared
);
117 // Se sabe que los puntos de interseccion estan ordenados correctamente
118 // porque el angulo de diferencia entre las semirectas es menor a 180,
119 // entonces no es necesario chequearlo.
124 return Intervalo(0, 0);
126 res
= Intervalo(0, p2
.valor
);
130 res
= Intervalo(p1
.valor
, 1);
132 res
= Intervalo(p1
.valor
, p2
.valor
);
136 res
= interseccion_intervalos(res
, Intervalo(0,1));
137 printf("Shadow: [%Lf, %Lf]\n",res
.first
* unidad
, res
.second
* unidad
);
138 return Intervalo(res
.first
* unidad
, res
.second
* unidad
);
141 void invertir_rango(const list
<Intervalo
>& ints
, long double fin
, list
<Intervalo
>& out
) {
144 out
.push_back(Intervalo(0,fin
));
149 list
<Intervalo
>::const_iterator it
= ints
.begin();
151 out
.push_back(Intervalo(0, it
->first
));
156 list
<Intervalo
>::const_iterator itprev
= ints
.begin();
157 while (it
!= ints
.end()) {
158 out
.push_back(Intervalo(itprev
->second
, it
->first
));
163 if (itprev
->second
< fin
) {
164 out
.push_back(Intervalo(itprev
->second
, fin
));
169 void reduce_union(list
<Intervalo
>& l_o
, list
<Intervalo
>& out
) {
170 // elimino repetidos para acelerar el sort
173 for (list
<Intervalo
>::const_iterator itcito
= l_o
.begin(); itcito
!= l_o
.end(); itcito
++) {
174 if (itcito
->first
< itcito
->second
) {
175 l
.push_back(Intervalo(itcito
->first
, itcito
->second
));
176 } else if (itcito
->first
> itcito
->second
) {
182 if (!l
.size()) return;
186 list
<Intervalo
>::const_iterator it
= l
.begin();
187 Intervalo cand
= *it
;
191 while (it
!= l
.end()) {
193 if (otro
.first
< otro
.second
) {
194 if (otro
.first
> cand
.second
) {
198 if (otro
.second
> cand
.second
) {
199 cand
= Intervalo(cand
.first
, otro
.second
);
210 long double resolver(const list
<Lampara
>& lamparas
, const list
<Columna
>& columnas
, int max_x
, int max_y
) {
211 list
<Segmento
> paredes
;
212 paredes
.push_back(Segmento(Vector(0,0), Vector(0, max_y
)));
213 paredes
.push_back(Segmento(Vector(0,max_y
), Vector(max_x
, max_y
)));
214 paredes
.push_back(Segmento(Vector(max_x
,max_y
), Vector(max_x
, 0)));
215 paredes
.push_back(Segmento(Vector(max_x
,0), Vector(0, 0)));
217 long double total
= 0;
219 for (list
<Segmento
>::iterator p
= paredes
.begin(); p
!= paredes
.end(); p
++) {
220 list
<Intervalo
> luces_pared
;
221 for (list
<Lampara
>::const_iterator l
= lamparas
.begin(); l
!= lamparas
.end(); l
++) {
222 list
<Intervalo
> zonas_tapadas
;
223 for (list
<Columna
>::const_iterator c
= columnas
.begin(); c
!= columnas
.end(); c
++) {
224 zonas_tapadas
.push_back(rango_oscurecido(*p
, *l
, *c
));
227 list
<Intervalo
> tapadas_unidas
;
228 list
<Intervalo
> zona_iluminada
;
230 reduce_union(zonas_tapadas
, tapadas_unidas
);
231 invertir_rango(tapadas_unidas
, largo(*p
), zona_iluminada
);
233 luces_pared
.splice(luces_pared
.end(), zona_iluminada
);
236 list
<Intervalo
> luces_pared_unidas
;
237 reduce_union(luces_pared
, luces_pared_unidas
);
239 for (list
<Intervalo
>::iterator it
= luces_pared_unidas
.begin(); it
!= luces_pared_unidas
.end(); it
++) {
240 printf("Lit: [%Lf, %Lf]\n", it
->first
, it
->second
);
251 int nl
, nc
, max_x
, max_y
;
254 scanf("%d %d %d %d", &nl
, &nc
, &max_x
, &max_y
);
256 if (!(nl
|| nc
|| max_x
|| max_y
)) {
260 list
<Vector
> lamparas
;
261 list
<Columna
> columnas
;
266 scanf("%d %d", &x
, &y
);
267 lamparas
.push_back(Lampara(x
,y
));
271 scanf("%d %d %d", &x
, &y
, &r
);
272 columnas
.push_back(Columna(x
, y
, r
));
275 printf("%.4Lf\n", resolver(lamparas
, columnas
, max_x
, max_y
));